package io.kblog.support

import org.springframework.web.method.support.HandlerMethodReturnValueHandler
import javax.servlet.http.HttpServletResponse
import org.springframework.web.context.request.NativeWebRequest
import org.springframework.web.method.support.ModelAndViewContainer
import org.springframework.core.MethodParameter
import org.springframework.http.MediaType
import org.springframework.lang.Nullable

open class JsonReturnHandler : HandlerMethodReturnValueHandler {
    override fun supportsReturnType(returnType: MethodParameter): Boolean {
        // 如果有我们自定义的 JSON 注解 就用我们这个Handler 来处理
        return (returnType.getMethodAnnotation(JSON::class.java) != null)
                || (returnType.declaringClass.getAnnotation(JSON::class.java) != null)
                || (returnType.getMethodAnnotation(JSONS::class.java) != null)
                || (returnType.declaringClass.getAnnotation(JSONS::class.java) != null)
    }

    override fun handleReturnValue(
        @Nullable returnValue: Any?,
        returnType: MethodParameter,
        mavContainer: ModelAndViewContainer,
        webRequest: NativeWebRequest
    ) {
        // 设置这个就是最终的处理类了，处理完不再去找下一个类进行处理
        mavContainer.isRequestHandled = true
        val annos = returnType.methodAnnotations.filter { it is JSON || it is JSONS }
            .ifEmpty { returnType.declaringClass.annotations.filter { it is JSON || it is JSONS } }
        val jsonSerializer = JacksonJsonSerializer()
        annos.forEach { // 解析注解，设置过滤条件
            if (it is JSON) {
                jsonSerializer.filter(it)
            } else if (it is JSONS) { // 使用多重注解时，实际返回的是 @Repeatable(JSONS.class) 内指定的 @JSONS 注解
                jsonSerializer.filter(*it.value)
            }
        }

        // 获得注解并执行filter方法 最后返回
        webRequest.getNativeResponse(HttpServletResponse::class.java)?.let { response ->
            response.contentType = MediaType.APPLICATION_JSON_VALUE
            response.characterEncoding = "UTF-8"
            response.writer.write(jsonSerializer.toJson(returnValue!!))
        }
    }
}